<?php
/*
 * Copyright 2010 Johannes M. Schmitt
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Class which provides some utilities for parsing, and working
 * with propertyMap generated by the compiler.
 * 
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class GoogleClosurePropertyMap 
{
	/**
	 * The property renaming map
	 * @var array
	 */
	private $_propertyMap;
	
	/**
	 * Constructor
	 * @param array $propertyMap
	 */
	private function __construct(array $propertyMap)
	{
		$this->_propertyMap = $propertyMap;
	}
	
	/**
	 * Whether the name has an optimized version. Note that the original name
	 * will not appear in the property map if the code in which it occurs has
	 * been considered "dead code" and consequentially has been removed by the 
	 * compiler.
	 * 
	 * @param string $name
	 * @return boolean
	 */
	public final function hasOptimizedName($name)
	{ 
		return isset($this->_propertyMap[$name]);
	}
	
	/**
	 * Returns the optimized name, or the original name if there is optimized
	 * version (@see hasOptimizedName()).
	 * 
	 * @param string $name the original name
	 * @return string
	 */
	public final function getOptimizedName($name)
	{
		return isset($this->_propertyMap[$name]) ?
			$this->_propertyMap[$name] : $name;
	}
	
	/**
	 * Parses the given file for a property renaming map.
	 * 
	 * WARNING:
	 * If the file ends with .php, this method assumes it to be the optimized 
	 * version of the property map, and will evaluate it as PHP code without 
	 * verifying the contents.
	 * 
	 * @param string $filePath
	 * @return GoogleClosurePropertyMap
	 */
	public final static function fromFile($filePath)
	{
		if (!file_exists($filePath) || !is_readable($filePath))
			throw new InvalidArgumentException(
				'Cannot read file located at: '. $filePath);
		
		$class = get_called_class();
		
		// check if this is the optimized version
		if (substr($filePath, -4) === '.php')
			return new $class(include $filePath);
		
		$propertyMap = array();
    	if (preg_match_all('/^([^:]+):([^\n]+)$/m', 
    		file_get_contents($filePath), 
    		$matches))
    	{
    		foreach ($matches[0] as $nb => $stuff)
    		{
    			$propertyMap[$matches[1][$nb]] = $matches[2][$nb];
    		}	
    	}
    	
    	return new $class($propertyMap);
	}
	
	/**
	 * Saves a version of the property map which is optimized for PHP
	 * 
	 * @param string $filePath The path where to save the file.
	 * @param boolean $create Whether to create the directory if it does not
	 *                        exist; defaults to true
	 */
	public final function save($filePath, $create = true, $createMode = 0755) 
	{
		if (substr($filePath, -4) !== '.php')
			throw new InvalidArgumentException('$filePath must end with ".php".');
		
		$dirname = dirname($filePath);
		if (!file_exists($dirname) || !is_dir($dirname))
		{
			if ($create === false)
				throw new RuntimeException('The directory does not exist.');
				
			if (@mkdir($filePath, true, $createMode) === false)
				throw new RuntimeException('Could not create directory: '. $directory);
		}
		
		file_put_contents($filePath, "<?php
/**
 * This file was created automatically by GoogleClosurePropertyMap.class.php
 * 
 * Do NOT modify it manually.
 */
return ".var_export($this->_propertyMap, true).";");
	}
}